﻿namespace ChinaUnicom.ViewModels
{
    using Avatar;
    using Avatar.Commands;
    using Avatar.Schedule;
    using ChinaUnicom.Models;
    using ChinaUnicom.Net;
    using ChinaUnicom.Tasks;
    using System;
    using System.Linq;
    using System.ComponentModel;
    using System.Windows;
    using System.Windows.Input;
    using ChinaUnicom.Controls;

    public enum PivotItemType
    {
        Package,
        Fee,
        FeeHitory
    }

    public class HomeContext : PageContext, INotifyPropertyChanged
    {
        const int FeeHistories_Show_ItemsCount = 6;
        const int FeeHistories_Load_ItemsCount = 8;

        PivotItemType currentPivotItem;

        ITaskScheduler scheduler;

        public HomeContext()
        {
            scheduler = SchedulerFactory.Create(SchedulerType.Serial);
            scheduler.Error += OnSchedulerError;
            scheduler.StateChanged += OnSchedulerStateChanged;

            Initialize();

            Package = new Package();
            Fee = new Fee();
            FeeHistories = new FeeHistoryCollection();

            currentPivotItem = PivotItemType.Package;

            if (Authentication.Current.Authorized)
            {
                var account = Context.Current.Account;
                Client = account.ClientName;
                Mobile = account.Mobile;
                MobileVisibility = Visibility.Visible;

                if (NetHelper.Network.IsNetworkAvailable && !Authentication.Current.Signed)
                {
                    // schedule autologin
                    scheduler.Schedule(GenerateAutologinTask());
                }
            }
        }

        public void ForceUpdate(PivotItemType type)
        {
            ITask task = null;
            switch (type)
            {
                case PivotItemType.Package:
                    task = GeneratePackageTask();
                    break;
                case PivotItemType.Fee:
                    task = GenerateFeeTask();
                    break;
            }

            scheduler.Schedule(task);
        }

        /// <summary>
        /// Auto update.
        /// </summary>
        /// <param name="type"></param>
        public void PivotSelectionChanged(PivotItemType type)
        {
            currentPivotItem = type;

            if (!Authentication.Current.Signed || !NetHelper.Network.IsNetworkAvailable) return;

            switch (type)
            {
                case PivotItemType.Package:
                    if (Package.Occurred.IsOutdated(30))
                    {
                        scheduler.Schedule(GeneratePackageTask());
                    }
                    break;

                case PivotItemType.Fee:
                    if (Context.Current.Fee.Occurred.IsOutdated())
                    {
                        scheduler.Schedule(GenerateFeeTask());
                    }
                    break;

                case PivotItemType.FeeHitory:
                    // get all fee histories.
                    scheduler.Schedule(GenerateFeeHistoriesTask());
                    break;
            }
        }

        #region Initialize

        void Initialize()
        {
            if (NetHelper.Network.IsNetworkAvailable)
            {
                OfflineVisibility = Visibility.Collapsed;
            }
            else
            {
                OfflineVisibility = Visibility.Visible;
            }

            Client = "未登录";
            MobileVisibility = Visibility.Collapsed;
            PackageContentVisibility = Visibility.Collapsed;
            FeeContentVisibility = Visibility.Collapsed;

            PackageProgressEnabled = false;
            FeeProgressEnabled = false;
            FeeHistoryProgressEnabled = false;
            PackageProgressVisibility = Visibility.Collapsed;
            FeeProgressVisibility = Visibility.Collapsed;
            FeeHistoryProgressVisibility = Visibility.Collapsed;

            PackagePullrefresh = "下拉可以刷新";
            FeePullrefresh = "下拉可以刷新";
        }

        public void Load()
        {
            Initialize();

            // Initialize Package
            if (Context.Current.Package.Items.Count != 0)
            {
                Package = Context.Current.Package;
                PackageContentVisibility = Visibility.Visible;
            }

            // Initialize Fee
            if (Context.Current.Fee.Items.Count != 0)
            {
                Fee = Context.Current.Fee;
                FeeContentVisibility = Visibility.Visible;
            }

            // Initialize FeeHistories
            if (Context.Current.FeeHistories.Count != 0)
            {
                FeeHistories.Partial(Context.Current.FeeHistories, FeeHistories_Show_ItemsCount);
            }

            // update Package
            if (Authentication.Current.Authorized)
            {
                var account = Context.Current.Account;
                Client = account.ClientName;
                Mobile = account.Mobile;
                MobileVisibility = Visibility.Visible;

                if (NetHelper.Network.IsNetworkAvailable && Package.Occurred.IsOutdated(30))
                {
                    scheduler.Schedule(GeneratePackageTask());
                }
            }
        }

        #endregion

        #region Tasks

        void OnSchedulerError(object sender, FailedEventArgs e)
        {
            Action<FailedEventArgs> action = args =>
            {
                Message.Tips(args.Exception.Message, "温馨提示");
            };

            action.UIThreadInvoke(e);
        }

        void OnSchedulerStateChanged(object sender, StateChangedArgs e)
        {
            if (e.State == ScheduleState.Done)
            {
                /*if (IsFeeHitoryUpdating)
                {
                    IsFeeHitoryUpdating = false;
                }*/

                Action action = () =>
                {
                    FeeHistoryProgressEnabled = false;
                    PackageProgressEnabled = false;
                    FeeProgressEnabled = false;
                };

                action.UIThreadInvoke();
            }
        }

        ITask GenerateAutologinTask()
        {
            ITask task = new AutologinTask();
            task.Failed += OnFailed;
            task.Completed += OnAutologinCompleted;

            return task;
        }

        ITask GeneratePackageTask()
        {
            if (!Authentication.Current.Signed)
            {
                scheduler.Schedule(GenerateAutologinTask());
            }

            ITask task = new PackageTask();
            task.Started += OnTaskStated;
            task.Failed += OnFailed;
            task.Completed += OnTaskCompleted;

            return task;
        }

        ITask GenerateFeeTask()
        {
            if (!Authentication.Current.Signed)
            {
                scheduler.Schedule(GenerateAutologinTask());
            }

            ITask task = new FeeTask();
            task.Started += OnTaskStated;
            task.Failed += OnFailed;
            task.Completed += OnTaskCompleted;

            return task;
        }

        ITask GenerateFeeHistoryTask(int your, int month)
        {
            if (!Authentication.Current.Signed)
            {
                scheduler.Schedule(GenerateAutologinTask());
            }

            ITask task = new FeeHistoryTask(your, month);
            task.Started += OnTaskStated;
            task.Failed += OnFailed;
            task.Completed += OnTaskCompleted;

            return task;
        }

        ITask GenerateFeeHistoriesTask()
        {
            if (!Authentication.Current.Signed)
            {
                scheduler.Schedule(GenerateAutologinTask());
            }

            FeeHistoriesTask task = new FeeHistoriesTask(FeeHistories_Load_ItemsCount);
            task.Started += OnTaskStated;
            task.Failed += OnFailed;
            task.Completed += OnTaskCompleted;
            task.Flashed += OnFlashed;

            return task;
        }

        void OnTaskStated(object sender, EventArgs e)
        {
            Action<ITask> action = task =>
            {
                switch (task.GetType().Name.ToLower())
                {
                    case "packagetask":
                        PackageProgressEnabled = true;
                        break;

                    case "feetask":
                        FeeProgressEnabled = true;
                        break;

                    case "feehistorytask":
                        FeeHistoryProgressEnabled = true;
                        break;

                    case "feehistoriestask":
                        FeeHistoryProgressEnabled = true;
                        break;
                }
            };

            action.UIThreadInvoke(sender as ITask);
        }

        void OnTaskCompleted(object sender, EventArgs e)
        {
            Action<ITask> action = task =>
            {
                switch (task.GetType().Name.ToLower())
                {
                    case "packagetask":
                        var p = task as PackageTask;
                        PackageContentVisibility = Visibility.Visible;
                        Package = p.Package;
                        Context.Current.Package = p.Package;
                        PackageProgressEnabled = false;
                        break;

                    case "feetask":
                        var f = task as FeeTask;
                        FeeContentVisibility = Visibility.Visible;
                        Fee = f.Fee;
                        Context.Current.Fee = f.Fee;
                        FeeProgressEnabled = false;
                        break;

                    case "feehistorytask":
                        var h = task as FeeHistoryTask;
                        if (!h.NotSupportedHistory)
                        {
                            Context.Current.FeeHistories.Add(h.History);
                            FeeHistories.Add(h.History);
                        }
                        break;
                    case "feehistoriestask":
                        var histories = Context.Current.FeeHistories
                                            .OrderByDescending(x => x.Occurred)
                                            .Take(FeeHistories_Show_ItemsCount);
                        FeeHistories.Clear();
                        FeeHistories.Add(histories);

                        FeeHistoryProgressEnabled = false;
                        break;
                }
            };

            action.UIThreadInvoke(sender as ITask);
        }

        void OnFailed(object sender, FailedEventArgs e)
        {
            Action<FailedEventArgs> action = args =>
            {
                Message.Tips(args.Exception.Message, "温馨提示");
            };

            action.UIThreadInvoke(e);
        }

        void OnAutologinCompleted(object sender, EventArgs e)
        {
            Action<AutologinTask> action = task =>
            {
            };

            action.UIThreadInvoke(sender as AutologinTask);
        }

        void OnFlashed(object sender, EventArgs e)
        {
            Action<FeeHistoryTask> action = task =>
            {
                if (!task.NotSupportedHistory)
                {
                    Context.Current.FeeHistories.Add(task.History);
                    if (FeeHistories.Count >= FeeHistories_Show_ItemsCount)
                    {
                        FeeHistories.HasMore = true;
                    }
                    else
                    {
                        FeeHistories.Add(task.History);
                    }
                }
            };

            action.UIThreadInvoke(sender as FeeHistoryTask);
        }

        #endregion

        #region ICommands
        Command loginCommand;
        public ICommand LoginCommand
        {
            get
            {
                if (loginCommand == null)
                {
                    loginCommand = new Command(param =>
                    {
                        // only network available to work.
                        if (!NetHelper.Network.IsNetworkAvailable)
                        {
                            return;
                        }

                        Navigate(new Uri("/Views/LoginPage.xaml", UriKind.Relative));
                    });

                    loginCommand.IsEnabled = false;
                }

                return loginCommand;
            }
        }

        Command searchCommand;
        public ICommand SearchCommand
        {
            get
            {
                if (searchCommand == null)
                {
                    searchCommand = new Command(param =>
                    {
                        Navigate(new Uri("/Views/SearchPage.xaml", UriKind.Relative));
                    });

                    searchCommand.IsEnabled = false;
                }

                return searchCommand;
            }
        }

        Command infoCommand;
        public ICommand InfoCommand
        {
            get
            {
                if (infoCommand == null)
                {
                    infoCommand = new Command(param =>
                    {
                        Navigate(new Uri("/Views/ClientInfoPage.xaml", UriKind.Relative));
                    });
                }

                return infoCommand;
            }
        }

        Command settingsCommand;
        public ICommand SettingsCommand
        {
            get
            {
                if (settingsCommand == null)
                {
                    settingsCommand = new Command(param =>
                    {
                        Navigate(new Uri("/Views/SettingsPage.xaml", UriKind.Relative));
                    });
                }

                return settingsCommand;
            }
        }

        Command statisticsCommand;
        public ICommand StatisticsCommand
        {
            get
            {
                if (statisticsCommand == null)
                {
                    statisticsCommand = new Command(param =>
                    {
                        Navigate(new Uri("/Views/StatisticsPage.xaml", UriKind.Relative));
                    });
                }

                return statisticsCommand;
            }
        }

        Command moreFeeHistoriesCommand;
        public ICommand MoreFeeHistoriesCommand
        {
            get
            {
                if (moreFeeHistoriesCommand == null)
                {
                    moreFeeHistoriesCommand = new Command(param =>
                    {
                        Navigate(new Uri("/Views/FeeHistoriesListPage.xaml", UriKind.Relative));
                    });
                }

                return moreFeeHistoriesCommand;
            }
        }

        Command listFeeHistoryCommand;
        public ICommand ListFeeHistoryCommand
        {
            get
            {
                if (listFeeHistoryCommand == null)
                {
                    listFeeHistoryCommand = new Command(param =>
                    {
                        DateTime occurred;
                        if (param != null && DateTime.TryParse(param.ToString(), out occurred))
                        {
                            Navigate(new Uri(string.Format("/Views/FeeHistoryPage.xaml?year={0}&month={1}", occurred.Year, occurred.Month), UriKind.Relative));
                        }
                    });
                }

                return listFeeHistoryCommand;
            }
        }
        #endregion

        #region properties

        string client;
        public string Client
        {
            get { return client; }
            set
            {
                if (value != client)
                {
                    client = value;
#if DEBUG
                    client = "张三";
#endif
                    NotifyPropertyChanged("Client");
                }
            }
        }

        string mobile;
        public string Mobile
        {
            get { return mobile; }
            set
            {
                if (value != mobile)
                {
                    mobile = value;
#if DEBUG
                    mobile = "18688888888";
#endif
                    NotifyPropertyChanged("Mobile");
                }
            }
        }

        Visibility mobileVisibility;
        public Visibility MobileVisibility
        {
            get { return mobileVisibility; }
            set
            {
                if (value != mobileVisibility)
                {
                    mobileVisibility = value;
                    NotifyPropertyChanged("MobileVisibility");
                }
            }
        }

        Visibility offlineVisibility;
        public Visibility OfflineVisibility
        {
            get { return offlineVisibility; }
            set
            {
                if (value != offlineVisibility)
                {
                    offlineVisibility = value;
                    NotifyPropertyChanged("OfflineVisibility");
                }
            }
        }

        Visibility packageContentVisibility;
        public Visibility PackageContentVisibility
        {
            get { return packageContentVisibility; }
            set
            {
                if (value != packageContentVisibility)
                {
                    packageContentVisibility = value;
                    NotifyPropertyChanged("PackageContentVisibility");
                }
            }
        }

        Package package;
        public Package Package
        {
            get { return package; }
            set
            {
                if (value != package)
                {
                    package = value;
                    NotifyPropertyChanged("Package");
                }
            }
        }

        Visibility feeContentVisibility;
        public Visibility FeeContentVisibility
        {
            get { return feeContentVisibility; }
            set
            {
                if (value != feeContentVisibility)
                {
                    feeContentVisibility = value;
                    NotifyPropertyChanged("FeeContentVisibility");
                }
            }
        }

        Fee fee;
        public Fee Fee
        {
            get { return fee; }
            set
            {
                if (value != fee)
                {
                    fee = value;
                    NotifyPropertyChanged("Fee");
                }
            }
        }

        FeeHistoryCollection feeHistories;
        public FeeHistoryCollection FeeHistories
        {
            get { return feeHistories; }
            set
            {
                if (value != feeHistories)
                {
                    feeHistories = value;
                    NotifyPropertyChanged("FeeHistories");
                }
            }
        }

        string packagePullrefresh;
        public string PackagePullrefresh
        {
            get { return packagePullrefresh; }
            set
            {
                if (value != packagePullrefresh)
                {
                    packagePullrefresh = value;
                    NotifyPropertyChanged("PackagePullrefresh");
                }
            }
        }

        string feePullrefresh;
        public string FeePullrefresh
        {
            get { return feePullrefresh; }
            set
            {
                if (value != feePullrefresh)
                {
                    feePullrefresh = value;
                    NotifyPropertyChanged("FeePullrefresh");
                }
            }
        }

        // progress bar.
        bool packageProgressEnabled;
        public bool PackageProgressEnabled
        {
            get { return packageProgressEnabled; }
            set
            {
                if (value != packageProgressEnabled)
                {
                    packageProgressEnabled = value;
                    NotifyPropertyChanged("PackageProgressEnabled");
                    ProgressVisibilitySwitch();
                }
            }
        }
        Visibility packageProgressVisibility;
        public Visibility PackageProgressVisibility
        {
            get { return packageProgressVisibility; }
            set
            {
                if (value != packageProgressVisibility)
                {
                    packageProgressVisibility = value;
                    NotifyPropertyChanged("PackageProgressVisibility");
                }
            }
        }

        bool feeProgressEnabled;
        public bool FeeProgressEnabled
        {
            get { return feeProgressEnabled; }
            set
            {
                if (value != feeProgressEnabled)
                {
                    feeProgressEnabled = value;
                    NotifyPropertyChanged("FeeProgressEnabled");
                    ProgressVisibilitySwitch();
                }
            }
        }
        Visibility feeProgressVisibility;
        public Visibility FeeProgressVisibility
        {
            get { return feeProgressVisibility; }
            set
            {
                if (value != feeProgressVisibility)
                {
                    feeProgressVisibility = value;
                    NotifyPropertyChanged("FeeProgressVisibility");
                }
            }
        }

        bool feeHistoryProgressEnabled;
        public bool FeeHistoryProgressEnabled
        {
            get { return feeHistoryProgressEnabled; }
            set
            {
                if (value != feeHistoryProgressEnabled)
                {
                    feeHistoryProgressEnabled = value;
                    NotifyPropertyChanged("FeeHistoryProgressEnabled");
                    ProgressVisibilitySwitch();
                }
            }
        }
        Visibility feeHistoryProgressVisibility;
        public Visibility FeeHistoryProgressVisibility
        {
            get { return feeHistoryProgressVisibility; }
            set
            {
                if (value != feeHistoryProgressVisibility)
                {
                    feeHistoryProgressVisibility = value;
                    NotifyPropertyChanged("FeeHistoryProgressVisibility");
                }
            }
        }

        void ProgressVisibilitySwitch()
        {
            PackageProgressVisibility = Visibility.Collapsed;
            FeeHistoryProgressVisibility = Visibility.Collapsed;
            FeeProgressVisibility = Visibility.Collapsed;

            switch (currentPivotItem)
            {
                case PivotItemType.Package:
                    if (PackageProgressEnabled)
                    {
                        PackageProgressVisibility = Visibility.Visible;
                    }
                    break;
                case PivotItemType.FeeHitory:
                    if (FeeHistoryProgressEnabled)
                    {
                        FeeHistoryProgressVisibility = Visibility.Visible;
                    }
                    break;
                case PivotItemType.Fee:
                    if (FeeProgressEnabled)
                    {
                        FeeProgressVisibility = Visibility.Visible;
                    }
                    break;
            }
        }

        #endregion

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (null != handler)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}
